import 'dart:async';
import 'dart:io';

import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
import 'package:ocr_plugin/ocr_rect_scanner_overlay_shape.dart';

import 'ocr_android_texture_view.dart';

const String PLAT_FORM_VIEW = "com.jacky.util/ocr_view";

typedef OcrRectViewCreatedCallback = void Function(OcrRecViewController);

///身份证ocr识别
class OcrRecView extends StatefulWidget {
  final OcrScannerOverlayShape? overlay;
  final EdgeInsetsGeometry overlayMargin;
  final OcrRectViewCreatedCallback onOcrRectViewCreated;
  final String? ocrHeadPath;

  /// 图片保存位置
  final String? ocrImgPath;
  /// 是否开启扫描
  final bool? scanEnable;
  /// 证件类型 0-身份证正面，1-身份证反面
  final int? type;
  /// 只对iOS有用，拍照是否需要旋转
  final bool? takePhotoRotated;

  ///只对Android有用 true表示页面竖向但横向识别，false表示横向页面横向识别
  ///androidUseImageOrientation==false&&portraitToLandscape==true，则拍照保存的图片会旋转90
  final bool portraitToLandscape;
  ///android 使用重力感应进行拍照旋转
  ///androidUseImageOrientation==true则根据重力感应，设置拍照保存的图片旋转角度
  final bool androidUseImageOrientation;
  final bool useTexture;

  /// 视图宽，准确值
  final double? areaWidth;
  /// 视图高，准确值
  final double? areaHeight;

  /// 自动停止扫描，只对iOS有用，scanEnable为true，
  final bool? iOSAutoStopScan;

  /// 头像视图，key，iOS用于身份证识别区域获取
  final GlobalKey? faceKey;

  /// 取景框满屏，或接近满屏
  final bool? iOSFullArea;

  const OcrRecView({
    required Key key,
    required this.onOcrRectViewCreated,
    this.overlayMargin = EdgeInsets.zero,
    this.overlay,
    this.ocrImgPath,
    this.ocrHeadPath,
    this.scanEnable = true,
    this.type = 0,
    this.takePhotoRotated = true,
    this.portraitToLandscape = true,
    this.androidUseImageOrientation = true,
    this.areaWidth = 0,
    this.areaHeight = 0,
    this.iOSAutoStopScan = true,
    this.faceKey,
    this.iOSFullArea = false,
    this.useTexture = false,  }) : super(key: key);

  @override
  State<StatefulWidget> createState() => OcrRecViewState();
}

class OcrRecViewState extends State<OcrRecView> with WidgetsBindingObserver{
  late MethodChannel _channel;
  OcrRecViewController? _controller;
  bool? _canUseTexture, _supportOcr;

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    _controller?.dispose();
    super.dispose();
  }

  @override
  void initState() {
    WidgetsBinding.instance.addObserver(this);
    if(Platform.isAndroid) {
      canUseTexture().then((value) {
        _canUseTexture = value['texture'];
        _supportOcr = value['ocr'];
        if (mounted) setState(() {});
      });
    } else {
      _canUseTexture = true;
      _supportOcr = true;
    }
    super.initState();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if(state == AppLifecycleState.paused){
      _controller?.pauseCamera();
    }else if(state == AppLifecycleState.resumed){
      _controller?.resumeCamera();
    }
    super.didChangeAppLifecycleState(state);
  }

  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        _platformView(),
        if (widget.overlay != null)
          Container(
            padding: widget.overlayMargin,
            decoration: ShapeDecoration(
              shape: widget.overlay!,
            ),
          )
      ],
    );
  }

  ///对应平台的view
  Widget _platformView() {
    if(_canUseTexture == null) return Container();
    final size =MediaQuery.of(context).size;
    final width =size.width;
    final height =size.height;

    print("_platformView width:$width, height:$height");

    /// 初始化视图所需参数
    var params = <String,dynamic>{
      "scanEnable": widget.scanEnable,
      "takePhotoRotated": widget.takePhotoRotated,
      "type": widget.type,
      "portraitToLandscape": widget.portraitToLandscape,
      "androidUseImageOrientation": widget.androidUseImageOrientation,
      "areaWidth": widget.areaWidth,
      "areaHeight": widget.areaHeight,
      "iOSAutoStopScan": widget.iOSAutoStopScan,
      "iOSFullArea": widget.iOSFullArea,
    };


    switch (defaultTargetPlatform) {
      case TargetPlatform.android:
        if(!widget.useTexture || _canUseTexture != true){
          return AndroidView(
            viewType: PLAT_FORM_VIEW,
            onPlatformViewCreated: _viewCreated,
            creationParams: params,
            creationParamsCodec: StandardMessageCodec(),
          );
        }
        final double v = _getDoubleAsFixed(_controller?.aspectRatio.value??0);
        final size = MediaQuery.of(context).size;
        final deviceRatio = _getDoubleAsFixed(size.width / size.height);
        // print("view w*h ${size.width} ${size.height} deviceRatio $deviceRatio aspectRatio $v "
        //     "${_controller?._previewWidth} ${_controller?._previewHeight} v/deviceRatio ${v/deviceRatio}");
        return ClipRRect(
          child: Center(
            child: Transform.scale(
              //pad的缩放 跟手机对换
              scale: v == 0 ? 1 :  widget.portraitToLandscape ? (v / deviceRatio) : (deviceRatio / v),
              child: AspectRatio(
                aspectRatio: v == 0 ? deviceRatio : v,
                child: Center(
                  child: RotatedBox(
                    // pad需要旋转，旋转次数,4次算一次循环
                    quarterTurns: widget.portraitToLandscape ? 0 : 3,
                    child: OcrAndroidTextureView(
                      onPlatformViewCreated: _viewCreated,
                      creationParams: params,
                    ),
                  ),
                ),
              ),
            ),
          ),
        );
      case TargetPlatform.iOS:
        return UiKitView(
            viewType: PLAT_FORM_VIEW,
            onPlatformViewCreated: _viewCreated,
            creationParams: params,
            creationParamsCodec: StandardMessageCodec());
      default:
        throw UnsupportedError(
            "Trying to use the default OcrRecView implementation "
            "for $defaultTargetPlatform but there isn't a default one");
    }
  }

  double _getDoubleAsFixed(double num,[int length = 3]){
    if(num == 0) return num;
    return double.tryParse(num.toStringAsFixed(length)) ?? 0;
  }

  void _viewCreated(int id) {
    var name = '${PLAT_FORM_VIEW}_$id';
    _channel = MethodChannel(name);
    // print("ocr rec view, flutter channel name $name");
    //类对象..  表示调用其方法并返回类对象本身
    _controller = OcrRecViewController._(_channel,
        ocrImgPath: widget.ocrImgPath, ocrHeadPath: widget.ocrHeadPath,portraitToLandscape: widget.portraitToLandscape, supportOcr: _supportOcr??true)
      .._startScan(
          widget.key as GlobalKey<State<StatefulWidget>>, widget.overlay, widget.faceKey as GlobalKey<State<StatefulWidget>>);
    _controller?.aspectRatio.addListener(() {
      if(_controller?.aspectRatio.value != null && mounted) setState(() {});
    });
    //返回
    widget.onOcrRectViewCreated(_controller!);

    if(Platform.isIOS){
      WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
        OcrRecViewController.updateDimensions(widget.key as GlobalKey<State<StatefulWidget>>, _channel,
            overlay:widget.overlay, faceKey: widget.faceKey as GlobalKey<State<StatefulWidget>>);
      });
    }
  }
}

///controller
class OcrRecViewController {
  final MethodChannel _channel;
  final String? _ocrImgPath;
  final String? _ocrHeadPath;
  final bool portraitToLandscape;
  final StreamController<dynamic> _scanUpdateController =
      StreamController<dynamic>();
  final ValueNotifier<double?> aspectRatio = ValueNotifier<double?>(null);

  int? _previewWidth;
  int? _previewHeight;
  bool _supportOcr;

  bool get supportOcr => _supportOcr;

  StreamController<dynamic> get scanUpdateController => _scanUpdateController;

  OcrRecViewController._(MethodChannel channel,
      {String? ocrImgPath, String? ocrHeadPath,this.portraitToLandscape = true, bool supportOcr = true})
      : _channel = channel,
        _ocrImgPath = ocrImgPath,
        _supportOcr = supportOcr,
        _ocrHeadPath = ocrHeadPath {
    _channel.setMethodCallHandler((call) async {
      switch (call.method) {
        case "onOcrRecognize":
          final args = call.arguments as Map;
          _scanUpdateController.sink.add(args);
          break;
        case "onOcrRectError":
          final args = call.arguments as Map;
          _scanUpdateController.sink.add(args);
          break;
        case "updatePreviewSize":
          _updatePreviewSize(call.arguments);
          break;
        default:
          print("ocr rect view no handle method ${call.method}");
          break;
      }
    });
  }

  ///更新相机预览画面的宽高尺寸
  _updatePreviewSize(arguments){
    var func = (value){
      return value is int ? value : int.tryParse("$value") ?? 0;
    };
    if(arguments is Map){
      int width = func(arguments['width']);
      int height = func(arguments['height']);
      if(width > 0 && height > 0 && width != this._previewWidth && height != this._previewHeight){
        this._previewWidth = width;
        this._previewHeight = height;
        var r = portraitToLandscape ? height * 1.0 / width : width * 1.0 / height;
        if(r != aspectRatio.value){
          aspectRatio.value = r;
        }
      }
    }
  }

  void dispose() {
    _stopCamera();
    _scanUpdateController.close();
  }

  /// Starts the barcode scanner
  Future<void> _startScan(
      GlobalKey key, OcrScannerOverlayShape? overlay, GlobalKey? faceKey) async {
    // We need to update the dimension before the scan is started.
    await OcrRecViewController.updateDimensions(key, _channel,
        overlay: overlay, faceKey: faceKey);
    return await _channel.invokeMethod(
        'startScan', {"ocrImgPath": _ocrImgPath, "ocrHeadPath": _ocrHeadPath});
  }

  /// Toggles the flashlight between available modes
  Future toggleFlash() async {
    return await _channel.invokeMethod('toggleFlash') as bool?;
  }

  /// Pauses the camera and barcode scanning
  Future pauseCamera() async {
    return await _channel.invokeMethod('pauseCamera');
  }

  /// Stops barcode scanning and the camera
  Future _stopCamera() async {
    return await _channel.invokeMethod('stopCamera');
  }

  /// Resumes barcode scanning
  Future resumeCamera() async {
    return await _channel.invokeMethod('resumeCamera');
  }

  /// 点击相册
  Future takePhotoLibrary() async {
    return await _channel.invokeMethod('takePhotoLibrary');
  }

  /// 点击拍照
  /// @params isWithRect 截取overlay区域的图片保存，返回路径
  Future takePhotoCamera({bool isWithRect = false}) async {
    return await _channel.invokeMethod('takePhotoCamera', {"isWithRect": isWithRect});
  }

  /// 点击切换摄像头
  Future switchCamera() async {
    return await _channel.invokeMethod('switchCamera');
  }

  /// Updates the view dimensions for iOS、Android.
  static Future<bool> updateDimensions(GlobalKey key, MethodChannel channel,
      {OcrScannerOverlayShape? overlay, GlobalKey? faceKey}) async {

    if (defaultTargetPlatform != TargetPlatform.iOS &&
        defaultTargetPlatform != TargetPlatform.android) {
      return false;
    }
    // Add small delay to ensure the render box is loaded
    await Future.delayed(Duration(milliseconds: 300));
    if (key.currentContext == null) return false;
    final renderBox = key.currentContext!.findRenderObject() as RenderBox;

    if (faceKey!=null && faceKey.currentContext != null) {
      final faceRenderBox = faceKey.currentContext!.findRenderObject() as RenderBox;
      await channel.invokeMethod('setDimensions', {
        'width': renderBox.size.width,
        'height': renderBox.size.height,

        'areaLeft': overlay?.recognizeRect.left ?? 0,
        'areaTop': overlay?.recognizeRect.top ?? 0,
        'areaWidth': overlay?.recognizeRect.width ?? 0,
        'areaHeight': overlay?.recognizeRect.height ?? 0,

        'faceLeft': faceRenderBox.localToGlobal(Offset.zero).dx,
        'faceTop': faceRenderBox.localToGlobal(Offset.zero).dy,
        'faceWidth': faceRenderBox.size.width,
        'faceHeight': faceRenderBox.size.height,
      });

      return true;
    }

    await channel.invokeMethod('setDimensions', {
      'width': renderBox.size.width,
      'height': renderBox.size.height,
      'areaLeft': overlay?.recognizeRect.left ?? 0,
      'areaTop': overlay?.recognizeRect.top ?? 0,
      'areaWidth': overlay?.recognizeRect.width ?? 0,
      'areaHeight': overlay?.recognizeRect.height ?? 0,
    });
    return true;
  }

  ///更新参数，主要是ocrImgPath更新路径
  Future updateParams(
      {bool? scanEnable,
      int? type,
      bool? takePhotoRotated,
      String? ocrImgPath,
      String? ocrHeadPath}) {
    return _channel.invokeMethod('updateParams', {
      if(scanEnable != null)'scanEnable': scanEnable,
      if(type != null)'type': type,
      if(takePhotoRotated != null)'takePhotoRotated': takePhotoRotated,
      if(ocrImgPath != null)'ocrImgPath': ocrImgPath,
      if(ocrHeadPath != null)'ocrHeadPath': ocrHeadPath,
    });
  }

}
